Strict

Import mojo

Global myGame:MyGame
Global Player : Ball
Global MoveSpeed : Float = 6.0
Global TurnSpeed : Float = 4.0

Global cBlock_List := New List<cBlock>
Global cCircle_List := New List<cCircle>

Function Main:Int()
	myGame = New MyGame
	Return 0
End Function


Class Ball

	Field x : Float
	Field y : Float

	Field angle : Float
	Field radius : Float

	Field oldx : Float
	Field oldy : Float

	Method New( x1 : Float, y1 : Float, r1 : Float )
		Self.x = x1
		Self.y = y1
		Self.radius = r1
	End Method

	Method Draw:Void()
		SetColor 255, 0, 0
		DrawOval( Self.x - Self.radius, Self.y - Self.radius, Self.radius * 2.0, Self.radius * 2.0 ) 
		SetColor 255, 255, 255
		DrawLine( Self.x, Self.y, Self.x + Sin( Self.angle ) * Self.radius, Self.y + Cos( Self.angle ) * Self.radius ) 
	End Method

End Class



Class cBlock

	Field x : Float
	Field y : Float
	Field w : Float
	Field h : Float

	Method New( x1 : Float, y1 : Float, w1 : Float, h1 : Float )
		Self.x = x1
		Self.y = y1
		Self.w = w1
		Self.h = h1
	End Method

	Method Draw:Void()
		DrawRect( Self.x - ( Self.w / 2.0 ), Self.y - ( Self.h / 2.0 ), Self.w, Self.h )
	End Method

	
	Function HandleCollision:Void()
		Local blockA : cBlock
		For blockA = Eachin cBlock_List
			Local halfW : Float = blockA.w / 2.0
			Local halfH : Float = blockA.h / 2.0
			If Abs( Player.x - blockA.x ) < ( halfW + Player.radius ) And Abs( Player.y - blockA.y ) < ( halfH + Player.radius )
				If Abs( Player.oldx - blockA.x ) < ( halfW + Player.radius )
					If Player.oldy < blockA.y Then Player.y = blockA.y - ( halfH + Player.radius )
					If Player.oldy > blockA.y Then Player.y = blockA.y + ( halfH + Player.radius )
				Endif
				If Abs( Player.oldy - blockA.y ) < ( halfH + Player.radius )
					If Player.oldx < blockA.x Then Player.x = blockA.x - ( halfW + Player.radius )
					If Player.oldx > blockA.x Then Player.x = blockA.x + ( halfW + Player.radius )
				Endif
			Endif
		Next
	End Function
	
End Class

Class cCircle

	Field x : Float
	Field y : Float

	Field radius : Float

	Method New( x1 : Float, y1 : Float, r1 : Float )
		Self.x = x1
		Self.y = y1
		Self.radius = r1
	End Method


	Method Draw:Void()
		DrawOval( Self.x - Self.radius, Self.y - Self.radius, Self.radius * 2.0, Self.radius * 2.0 )
	End Method
	
	
	Function HandleCollision:Void()
		Local circleA : cCircle
		For circleA = Eachin cCircle_List
			Local dx : Float = Player.x - circleA.x
			Local dy : Float = Player.y - circleA.y
			Local r : Float = Sqrt(( dx * dx ) + ( dy * dy ))
			Local totalR:Float = circleA.radius + Player.radius
			If r < totalR
				Local pDir:Float = ATan2( dy, dx )
				Player.x = circleA.x + ( Cos( pDir ) * totalR )
				Player.y = circleA.y + ( Sin( pDir ) * totalR )
			Endif
		Next
	End Function

End Class

Class MyGame Extends App

	Method OnCreate:Int()
		SetUpdateRate 60
		
		'create a player
		Player = New Ball( 40, 40, 20 )
		
		'create some boxes
		Local blockA : cBlock
		blockA = New cBlock( 200, 310, 100, 220 )
		cBlock_List.AddLast( blockA )
		blockA = New cBlock( 200, 200, 200, 80 )
		cBlock_List.AddLast( blockA )
		
		'create some circles
		Local circleA : cCircle
		circleA = New cCircle( 450, 320, 100 )
		cCircle_List.AddLast( circleA )
		
		Return 0
	End
	
	Method OnUpdate:Int()
		'grab old position
		Player.oldx = Player.x
		Player.oldy = Player.y
	
	
		'grab device size
		Local dw : Int = DeviceWidth()
		Local dh : Int = DeviceHeight()
		
		
		'update movement
		If KeyDown( KEY_UP )
			Player.x = Player.x + Sin( Player.angle ) * MoveSpeed
			Player.y = Player.y + Cos( Player.angle ) * MoveSpeed
		Endif
		If KeyDown( KEY_DOWN )
			Player.x = Player.x - Sin( Player.angle ) * MoveSpeed
			Player.y = Player.y - Cos( Player.angle ) * MoveSpeed
		Endif
		If KeyDown( KEY_LEFT ) Then Player.angle = Player.angle + TurnSpeed
		If KeyDown( KEY_RIGHT ) Then Player.angle = Player.angle - TurnSpeed

		
		'sliding box collision
		cBlock.HandleCollision()


		'sliding circle collision
		cCircle.HandleCollision()

	
		'collision with edges of screen
		If Player.x < Player.radius Then Player.x = Player.radius
		If Player.y < Player.radius Then Player.y = Player.radius
		If Player.x > dw - Player.radius Then Player.x = dw - Player.radius
		If Player.y > dh - Player.radius Then Player.y = dh - Player.radius

		
		Return 0
	End
	
	Method OnRender:Int()
		'clear screen
		Cls 0, 0, 0
	
		'draw the player
		If Player
			Player.Draw()		
		Endif
	
		'draws cblocks
		Local blockA : cBlock
		SetColor 255, 255, 255
		For blockA = Eachin cBlock_List
			blockA.Draw()
		Next
	
		'draws cCircles
		Local circleA : cCircle
		For circleA = Eachin cCircle_List
			circleA.Draw()
		Next
		Return 0
	End	
End

